package cn.colat.micse.common.handler;

import cn.colat.micse.common.code.ResCode;
import cn.colat.micse.common.exception.GlobalServerException;
import cn.colat.micse.common.pojo.vo.ResBody;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.naming.NoPermissionException;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 无角色异常
    @ExceptionHandler
    public ResBody<Object> notRoleException(NotRoleException e) {
        log.warn("用户：{}，不是[{}]角色", StpUtil.getLoginId(), e.getRole());
        return ResBody.failErrorCode(ResCode.NO_ROLE, e.getRole());
    }

    // 无权限异常
    @ExceptionHandler
    public ResBody<Object> notPermissionException(NoPermissionException e) {
        log.warn("用户：{}，没有权限：[{}]", StpUtil.getLoginId(), e.getMessage());
        return ResBody.failErrorCode(ResCode.NO_PERMISSION, e.getMessage());
    }

    // 缺少必要参数
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public ResBody<Object> missingParameterHandler(HttpServletRequest request, MissingServletRequestParameterException e) {
        log.error("缺少必要参数：{}", e.getMessage());
        return ResBody.failErrorCode(ResCode.MISSING_PARAMETER);
    }

    // 参数类型不匹配
    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
    public ResBody<Object> methodArgumentTypeMismatchException(HttpServletRequest request, MethodArgumentTypeMismatchException e) {
        log.error("参数类型不匹配：{}", e.getMessage());
        return ResBody.failErrorCode(ResCode.ARGUMENT_TYPE_MISMATCH);
    }

    // 不支持的请求方法
    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
    public ResBody<Object> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
        StringBuilder sb = new StringBuilder();
        e.getMethod();
        String[] ms = e.getSupportedMethods();
        if (ms != null && ms.length > 0) {
            for (String m : ms) {
                sb.append("[").append(m).append("]").append(",");
            }
            sb.deleteCharAt(sb.length() - 1);
        }
        return ResBody.failErrorCode(ResCode.HTTP_METHOD_NOT_SUPPORTED, e.getMethod(), sb.toString());
    }

    // 参数错误
    @ExceptionHandler(value = IllegalArgumentException.class)
    public ResBody<Object> illegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
        return ResBody.failErrorCode(ResCode.ILLEGAL_ARGUMENTS);
    }

    // 参数校验异常处理
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResBody<Object> handle(MethodArgumentNotValidException e) {
        log.error("参数校验异常：{}", e.getMessage());
        return ResBody.failErrorCode(ResCode.ILLEGAL_ARGUMENTS);
    }

    // 参数绑定异常处理
    @ExceptionHandler(BindException.class)
    public ResBody<Object> handle(BindException e) {
        log.error("参数绑定异常：{}", e.getMessage());
        return ResBody.failErrorCode(ResCode.ILLEGAL_ARGUMENTS);
    }

    // 参数校验异常处理
    @ExceptionHandler(ConstraintViolationException.class)
    public ResBody<Object> handle(ConstraintViolationException e) {
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<?> violation : e.getConstraintViolations()) {
            sb.append(violation.getMessage()).append("; ");
        }
        log.error("参数校验异常：{}", sb);
        return ResBody.failErrorCode(ResCode.PARAMETER_VIOLATION_ERROR.format(sb));
    }

    // 业务异常处理
    @ExceptionHandler(value = GlobalServerException.class)
    public ResBody<Object> businessException(HttpServletRequest request, GlobalServerException e) {
        log.error("path:{}, queryParam:{},errorCode:{} message:{}",
                request.getRequestURI(),
                request.getQueryString(),
                e.getCode(),
                e.getMessage());
        return ResBody.failMessage(e.getCode(), e.getCodeText(), e.getMessage());
    }

    // 未登录异常处理
    @ExceptionHandler(value = NotLoginException.class)
    public ResBody<Object> businessException(NotLoginException e) {
        return ResBody.failErrorCode(ResCode.NO_LOGIN);
    }

    // 其他异常统一处理
    @ExceptionHandler(value = Throwable.class)
    public ResBody<Object> exception(HttpServletRequest request, Throwable e) {
        log.error("系统出现无法捕获的Throwable异常：{}", e.getMessage());
        e.printStackTrace();
        return ResBody.failErrorCode(ResCode.SERVER_ERROR);
    }

    // 其他异常统一处理
    @ExceptionHandler(value = Error.class)
    public ResBody<Object> error(HttpServletRequest request, Error e) {
        log.error("系统出现无法捕获的Error异常：{}", e.getMessage());
        e.printStackTrace();
        return ResBody.failErrorCode(ResCode.SERVER_ERROR);
    }
}
